<?php
namespace app\admin\traits;

use think\exception\ValidateException;
use think\Validate;

trait ValidateTrait
{
    /**
     * 增强型场景验证
     * @param string $scene 场景名称
     * @param array $data 验证数据
     * @param bool $batch 是否批量验证
     * @return array
     * @throws ValidateException
     */
    protected function autoValidate(
        string $scene,
        array $data = [],
        bool $batch = false
    ): array {
        $config = $this->parseSceneConfig($scene);

        $validator = new Validate();
        $validator->rule($config['rules'])
            ->message(array_merge($this->getMessages(), $config['messages']))
            ->field($config['attributes']);

        if ($batch) {
            $validator->batch(true);
        }

        $data = $data ?: request()->param();

        if (!$validator->check($data)) {
            $errors = (array)$validator->getError();
            // 优化点1：清理消息末尾标点
            $errorMsg = implode(', ', array_map(function($v) {
                return rtrim($v, ',，');
            }, $errors));

            throw new ValidateException($errorMsg);
        }

        return $data;
    }

    /**
     * 场景配置解析器（支持10种配置格式）
     */
    private function parseSceneConfig(string $scene): array
    {
        // 防御性编程：检查必要属性
        if (!property_exists($this, 'validationScenes')) {
            throw new ValidateException("必须定义validationScenes属性");
        }

        $scenes = $this->validationScenes;

        // 场景存在性检查
        if (!isset($scenes[$scene])) {
            throw new ValidateException("验证场景[{$scene}]未定义");
        }

        $rules = [];
        $attributes = [];
        $messages = [];
        $globalAttributes = $this->validationAttributes ?? [];

        foreach ($scenes[$scene] as $field => $config) {
            // +++ 新增优化点：强化索引数组处理 +++
            if (is_array($config) && isset($config[0]) && isset($config[1])) {
                $ruleStr = is_string($config[0])?explode('|', $config[0]):$config[0];
                $fieldName = $config[1]; // 直接使用场景配置中的字段别名
                $sceneMessages = $config[2] ?? [];

                // 规则处理
                $rules[$field] = $this->normalizeRule($ruleStr);

                // 字段别名（优先使用场景配置，不再依赖全局validationAttributes）
                $attributes[$field] = $fieldName;

                // 自动生成规则级消息键
                foreach ($ruleStr as $ruleItem) {
                    $ruleName = explode(':', $ruleItem)[0];
                    if (isset($this->getMessages()[$ruleName])) {
                        $msgKey = "{$field}.{$ruleName}";
                        // 优先使用场景消息，其次自动替换全局模板
                        if (!isset($sceneMessages[$ruleName])) {
                            $messages[$msgKey] = str_replace(
                                [':attribute', ':rule'],
                                [$fieldName, explode(':', $ruleItem)[1] ?? ''],
                                $this->getMessages()[$ruleName]
                            );
                        } else {
                            $messages[$msgKey] = $sceneMessages[$ruleName];
                        }
                    }
                }
                continue;
            }

            // 处理完整数组配置（支持5种子格式）
            if (is_array($config)) {
                // 规则提取（支持索引数组和关联数组）
                $rule = $config['rule'] ?? $config[0] ?? '';

                // 闭包规则特殊处理
                if ($rule instanceof \Closure) {
                    $rules[$field] = $rule;
                } else {
                    $rules[$field] = $this->normalizeRule($rule);
                }

                // 字段别名处理（支持全局和场景专用）
                $attributes[$field] = $config['name'] ?? $config[1] ?? $globalAttributes[$field] ?? $field;

                // 消息处理（支持字段级和规则级消息）
                if (isset($config['message']) || isset($config[2])) {
                    $message = $config['message'] ?? $config[2];

                    // 处理多维消息数组
                    if (is_array($message)) {
                        foreach ($message as $ruleName => $msg) {
                            $key = "{$field}.{$ruleName}";
                            $messages[$key] = $msg;
                        }
                    } else {
                        // 自动关联首条规则
                        $firstRule = $this->getFirstRuleName($rules[$field]);
                        if ($firstRule) {
                            $messages["{$field}.{$firstRule}"] = $message;
                        }
                    }
                }
            }
        }

        return [
            'rules' => $rules,
            'attributes' => $attributes,
            'messages' => $messages
        ];
    }

    /**
     * 规则标准化处理器（支持8种规则格式）
     */
    private function normalizeRule($rule)
    {
        // 保留闭包规则
        if ($rule instanceof \Closure) {
            return $rule;
        }

        // 处理数组规则（包括关联数组）
        if (is_array($rule)) {
            $processed = [];
            foreach ($rule as $key => $value) {
                // 处理关联数组规则（如 ['in' => [1,2,3], 'between' => '1,100']）
                if (!is_numeric($key)) {
                    $param = is_array($value) ? implode(',', $value) : $value;
                    $processed[] = "{$key}:{$param}";
                } else {
                    // 处理索引数组元素（如 ['require', 'max:20']）
                    $processed[] = $value;
                }
            }
            return implode('|', $processed);
        }

        // 处理字符串规则（自动转换数组格式）
        if (is_string($rule)) {
            return strpos($rule, '|') !== false ? explode('|', $rule) : $rule;
        }

        return $rule;
    }

    /**
     * 获取首条规则名称（用于消息自动关联）
     */
    private function getFirstRuleName($rule): string
    {
        if ($rule instanceof \Closure) {
            return 'closure';
        }

        if (is_array($rule)) {
            $first = $rule[0] ?? '';
            return is_string($first) ? explode(':', $first)[0] : '';
        }

        if (is_string($rule)) {
            return explode(':', $rule)[0];
        }

        return '';
    }

    /**
     * 增强型验证消息模板（包含36种常见规则）
     */
    private function getMessages(): array
    {
        return [
            // 基础验证
            'require'     => ':attribute必须填写',
            'accepted'    => ':attribute必须接受',
            'date'        => ':attribute不是有效日期',

            // 类型验证
            'number'      => ':attribute必须是数字',
            'integer'     => ':attribute必须是整数',
            'float'       => ':attribute必须是浮点数',
            'boolean'     => ':attribute必须是布尔值',
            'array'       => ':attribute必须是数组',
            'object'      => ':attribute必须是对象',

            // 格式验证
            'email'       => ':attribute邮箱格式错误',
            'mobile'      => ':attribute手机号格式错误',
            'idCard'      => ':attribute身份证号格式错误',
            'zip'         => ':attribute邮政编码格式错误',
            'url'         => ':attribute网址格式错误',
            'ip'          => ':attributeIP地址格式错误',
            'dateFormat'  => ':attribute必须符合格式 :rule',
            'regex'       => ':attribute格式不符合要求',

            // 范围验证
            'in'          => ':attribute必须在 :rule 范围内',
            'notIn'       => ':attribute不能在 :rule 范围内',
            'between'     => ':attribute必须介于 :1 - :2 之间',
            'notBetween'  => ':attribute不能介于 :1 - :2 之间',
            'length'      => ':attribute长度必须为 :rule 个字符',
            'max'         => ':attribute长度不能超过 :rule 个字符',
            'min'         => ':attribute长度不能少于 :rule 个字符',

            // 比较验证
            'confirm'     => ':attribute两次输入不一致',
            'different'   => ':attribute必须和 :rule 不同',
            'eq'          => ':attribute必须等于 :rule',
            'gt'          => ':attribute必须大于 :rule',
            'egt'         => ':attribute必须大于等于 :rule',
            'lt'          => ':attribute必须小于 :rule',
            'elt'         => ':attribute必须小于等于 :rule',

            // 文件验证
            'file'        => ':attribute必须是文件',
            'image'       => ':attribute必须是图片',
            'fileSize'    => ':attribute文件大小不能超过 :rule',
            'fileExt'     => ':attribute文件扩展名必须是 :rule',
            'fileMime'    => ':attribute文件类型必须是 :rule',

            // 数据库验证
            'unique'      => ':attribute已存在',
            'exist'       => ':attribute不存在',

            // 特殊验证
            'filter'      => ':attribute包含非法内容',
            'behavior'    => ':attribute行为验证失败',
            'json'        => ':attribute必须是JSON字符串',
            'token'       => ':attribute令牌无效'
        ];
    }
}
